use std::{cell::RefCell, collections::BTreeMap, collections::HashMap, sync::Arc, sync::Mutex, thread};

use crossbeam::channel::{self, Sender};
use log::info;
use crate::domain::order_do::OrderUpdateDO;

lazy_static! {
    static ref ENGINE_MAP: Arc<Mutex<HashMap<String, EngineLink>>> =
        Arc::new(Mutex::new(HashMap::new()));
}
pub type Job = Box<dyn FnOnce() + Send + 'static>;
struct EngineLink {
    engine: Engine,
    buy_map:BTreeMap<String,OrderUpdateDO>,
    sell_map:BTreeMap<String,OrderUpdateDO>,
}

pub fn handle(order: OrderUpdateDO) -> Result<String, String> {
    let mut em = ENGINE_MAP.lock().unwrap();
    // let mut bm=BUY_MAP.lock().unwrap();
    let symbol = order.get_symbol().unwrap().clone();
    if !em.contains_key(&symbol) {
        let engine = Engine::new(symbol.clone());
        let engine_link = EngineLink {
            engine,
            buy_map:BTreeMap::<String,OrderUpdateDO>::new(),
            sell_map:BTreeMap::<String,OrderUpdateDO>::new(),
        };
        em.insert(symbol.clone(), engine_link);
        // bm.insert(symbol.clone(), )
    }
    let e = &em.get(symbol.as_str()).unwrap().engine;
    e.put_order(order);
    Ok("处理成功".to_string())
}


pub struct Engine {
    pub symbol: String,
    thread: thread::JoinHandle<()>,
    tx: Sender<Job>,
}



impl Engine {
    pub fn new(symbol: String) -> Engine {
        let (tx, rx) = channel::unbounded::<Job>();
        let thread = thread::spawn(move || loop {
            let job = rx.recv().unwrap();
            job();
        });
        //开启线程撮合.
        Engine {
            symbol,
            thread,
            tx,
        }
    }

    pub fn put_order(&self, order: OrderUpdateDO) {
        self.tx
            .send(Box::new(move || {
                match_order( order);
            }))
            .unwrap();
    }
}

fn match_order(order: OrderUpdateDO) {
    let mut em = ENGINE_MAP.lock().unwrap();
    let engine_link = em.get_mut(order.symbol.as_str()).unwrap();
    // engine_link.insert(order.clone());
    engine_link.sell_map.insert(order.price.to_string(), order);
    info!("engine_link.sell_map is:{:?}",engine_link.sell_map);
}
